home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dcpp
/
cexp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
13KB
|
702 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* CEXP.C
*
*/
#include "defs.h"
Prototype long ParseIfExp(char *, short *, long, short);
Prototype void PushOp(short, short, short);
Prototype int TopOfOpStack(void);
Prototype int SecondOffOpStack(void);
Prototype void PushAtom(long, short);
Local int CombineOp(void);
Local int GetAtomStack(short *, long *);
Local int ParseCharConst(char *, long, long, long *);
Local int ParseInt(char *, long, long, long *);
Local int HexDig(char);
Local int OctDig(char);
#define MAXATOM 128
#define MAXOPER 128
#define CGTEQ 256
#define CGTGT 257
#define CLTEQ 258
#define CLTLT 259
#define CNOTEQ 260
#define CEQEQ 261
#define CSYM 262
#define CUMI 263
#define CDEFINED 264
#define CANDAND 265
#define COROR 266
#define QBIN 4 /* binary operator, else unary */
#define LR 1 /* left to right, else */
#define RL 2 /* right to left */
#define BLR (LR|QBIN)
#define BRL (RL|QBIN)
#define XX 0
typedef struct Atom {
long Value;
short Undef;
short Reserved;
} Atom;
typedef struct Oper {
short Token;
short Pri;
short Type;
short Reserved;
} Oper;
static Atom AtomStack[MAXATOM];
static Oper OperStack[MAXOPER];
static short AtomIdx;
static short OperIdx;
static short BaseAtomIdx;
static short BaseOperIdx;
long
ParseIfExp(char *buf, short *pundef, long max, short subsym)
{
short unary = 1;
short i = 0;
short parens = 0;
short baseOperIdx;
short baseAtomIdx;
baseOperIdx = BaseOperIdx = OperIdx;
baseAtomIdx = BaseAtomIdx = AtomIdx;
while (i < max) {
short c = buf[i];
++i;
if (c == ' ' || c == 9 || c == '\n')
continue;
if (unary) { /* int, sym, !exp, ~exp (exp) */
switch(c) {
case '!':
case '~':
PushOp(c, 140, RL);
break;
case '-':
PushOp(CUMI, 140, RL);
break;
case '(':
++parens;
PushOp(c, 0, XX);
break;
default:
if (c >= '0' && c <= '9') {
long v;
/*
printf("%d(%c) ", i - 1, buf[i-1]);
*/
i = ParseInt(buf, i - 1, max, &v);
/*
printf("%d INT %d\n", i, v);
*/
PushAtom(v, 0);
unary = 0;
break;
}
/*
* NOTE, handles 'defined' by pushing unary op instead
* of atom.
*/
if (SymbolChar[c]) { /* SymbolChar[] includes '0'-'9' */
short ni;
--i;
ni = ExtSymbol(buf, i, max);
if (ni - i == 7 && strncmp(buf + i, "defined", 7) == 0) {
PushOp(CDEFINED, 140, RL);
} else if (TopOfOpStack() == CDEFINED || SecondOffOpStack() == CDEFINED) {
Sym *sym = FindSymbol(buf + i, ni - i);
if (sym)
PushAtom(1, 0);
else
PushAtom(0, 1);
unary = 0;
} else {
Sym *sym = FindSymbol(buf + i, ni - i);
if (sym) {
short xundef;
long v;
if (subsym == 0) {
v = 0;
xundef = 0;
} else {
/* We need to actually parse the symbol and then */
/* evaluate any arguments. This code closely */
/* mimics the code found in HandleSymbol, but it */
/* has the additional requirement of not actually */
/* sending anything out to the output file. */
short oldType = sym->Type;
short creType = 0;
{
long it = ni;
/* The -max is so that we can flag to the */
/* routine to not output anything */
if (PrepareSymbolArgs(sym, buf, &it, -max) == NULL)
goto syntax;
ni = it;
}
/*
* If pushing a macro argument for replace we must
* enable the macro it came from. This allows
* MAX(MAX(1,2),3) while disallowing loop conditions,
* i.e. #define BAR(x) BAR(1,x)
*/
if (sym->Type & SF_MACROARG) {
if (sym->Creator == NULL)
cerror(EFATAL_SOFTWARE_ERROR_CREATOR);
creType = sym->Creator->Type;
sym->Creator->Type &= ~SF_RECURSE;
}
v = ParseIfExp(sym->Text, &xundef, sym->TextLen, 1);
if (sym->Type & SF_MACROARG)
sym->Creator->Type = creType;
if (sym->NumArgs >= 0)
{ /* undef symbol args symbols */
short j;
for (j = 0; j < sym->NumArgs; ++j)
{
if (UndefSymbol(sym->Args[j], sym->ArgsLen[j]) == 0)
cerror(EFATAL_SOFTWARE_ERROR_MACRO,
sym->SymName, sym->Args[j]);
}
}
sym->Type = oldType;
BaseOperIdx = baseOperIdx;
BaseAtomIdx = baseAtomIdx;
}
PushAtom(v, xundef);
} else {
PushAtom(0, 1);
}
unary = 0;
}
i = ni;
break;
}
if (c == '\'') {
long v;
i = ParseCharConst(buf, i - 1, max, &v);
PushAtom(v, 0);
unary = 0;
break;
}
syntax:
cerror(EERROR_SYNTAX_ERROR);
syntax2:
*pundef = 1;
AtomIdx = baseAtomIdx;
OperIdx = baseOperIdx;
return(0);
}
} else { /* + - * / % & | ^ <= << < == != > >> >= */
unary = 1;
switch(c) {
case '+':
case '-':
PushOp(c, 120, BLR);
break;
case '*':
case '/':
case '%':
PushOp(c, 130, BLR);
break;
case '&':
if (i < max && buf[i] == '&') {
PushOp(CANDAND, 50, BLR);
++i;
} else {
PushOp(c, 60, BLR);
}
break;
case '^':
PushOp(c, 70, BLR);
break;
case '|':
if (i < max && buf[i] == '|') {
++i;
PushOp(COROR, 40, BLR);
} else {
PushOp(c, 80, BLR);
}
break;
case '<':
if (i < max) {
short d = buf[i];
if (d == '<') {
PushOp(CLTLT, 110, BLR);
++i;
break;
}
if (d == '=') {
PushOp(CLTEQ, 100, BLR);
++i;
break;
}
}
PushOp(c, 100, BLR);
break;
case '=':
if (i >= max || buf[i] != '=')
goto syntax;
PushOp(CEQEQ, 90, BLR);
++i;
break;
case '!':
if (i >= max || buf[i] != '=')
goto syntax;
PushOp(CNOTEQ, 90, BLR);
++i;
break;
case '>':
if (i < max) {
short d = buf[i];
if (d == '>') {
PushOp(CGTGT, 110, BLR);
++i;
break;
}
if (d == '=') {
PushOp(CGTEQ, 100, BLR);
++i;
break;
}
}
PushOp(c, 100, BLR);
break;
case ')':
unary = 0;
if (parens == 0) {
cerror(EERROR_TOO_MANY_CLOSE_PARENS);
goto syntax2;
}
--parens;
while ((c = TopOfOpStack()) && c != '(')
CombineOp();
if (c == 0)
goto syntax;
CombineOp();
break;
default:
goto syntax;
}
}
}
while (TopOfOpStack() >= 0 && CombineOp() >= 0);
if (TopOfOpStack() >= 0)
goto syntax;
{
long v;
if (GetAtomStack(pundef, &v) < 0)
goto syntax;
if (GetAtomStack(NULL, NULL) >= 0) /* shouldn't be anything left */
goto syntax;
AtomIdx = baseAtomIdx;
OperIdx = baseOperIdx;
dbprintf(("RESULT %ld %d\n", v, *pundef));
return(v);
}
}
void
PushOp(short token, short pri, short type)
{
if (pri) {
while (OperIdx > BaseOperIdx) {
Oper *op = OperStack + OperIdx - 1;
if (pri > op->Pri)
break;
if (pri == op->Pri && (type & RL))
break;
if (CombineOp() < 0) {
cerror(EERROR_SYNTAX_ERROR);
break;
}
}
}
if (OperIdx == MAXOPER) {
cerror(EERROR_EXPRESSION_TOO_COMPLEX);
return;
}
{
Oper *op = OperStack + OperIdx++;
op->Pri = pri;
op->Token = token;
op->Type = type;
}
}
int
TopOfOpStack()
{
if (OperIdx <= BaseOperIdx)
return(-1);
return((int)OperStack[OperIdx-1].Token);
}
int
SecondOffOpStack()
{
if (OperIdx - 1 <= BaseOperIdx)
return(-1);
return((int)OperStack[OperIdx-2].Token);
}
void
PushAtom(long val, short isundef)
{
Atom *atom;
if (AtomIdx == MAXATOM) {
cerror(EERROR_EXPRESSION_TOO_COMPLEX);
return;
}
atom = AtomStack + AtomIdx++;
atom->Value = val;
atom->Undef = isundef;
}
int
CombineOp()
{
Oper *op;
Atom *a1, *a2;
Atom ar;
if (OperIdx <= BaseOperIdx)
return(-1);
op = OperStack + --OperIdx;
if (AtomIdx <= BaseAtomIdx)
return(-1);
a1 = AtomStack + --AtomIdx;
if (op->Type & QBIN) {
if (AtomIdx <= BaseAtomIdx)
return(-1);
a2 = AtomStack + --AtomIdx;
}
if (op->Type & QBIN) {
ar.Undef = a1->Undef | a2->Undef;
switch(op->Token) {
case '+':
ar.Value = a2->Value + a1->Value;
break;
case '-':
ar.Value = a2->Value - a1->Value;
break;
case '*':
ar.Value = a2->Value * a1->Value;
break;
case '/':
if (a1->Value)
ar.Value = a2->Value / a1->Value;
else
ar.Undef = 1;
break;
case '%':
if (a1->Value)
ar.Value = a2->Value % a1->Value;
else
ar.Undef = 1;
break;
case '&':
ar.Value = a2->Value & a1->Value;
break;
case '|':
ar.Value = a2->Value | a1->Value;
break;
case '^':
ar.Value = a2->Value ^ a1->Value;
break;
case '<':
ar.Value = a2->Value < a1->Value;
break;
case CLTLT:
ar.Value = a2->Value << a1->Value;
break;
case CLTEQ:
ar.Value = a2->Value <= a1->Value;
break;
case CEQEQ:
ar.Value = a2->Value == a1->Value;
break;
case CNOTEQ:
ar.Value = a2->Value != a1->Value;
break;
case '>':
ar.Value = a2->Value > a1->Value;
break;
case CGTGT:
ar.Value = a2->Value >> a1->Value;
break;
case CGTEQ:
ar.Value = a2->Value >= a1->Value;
break;
case CANDAND:
if (a2->Value && a1->Value)
ar.Value = 1;
else
ar.Value = 0;
break;
case COROR:
if (a2->Undef == 0 && a2->Value) {
ar.Value = 1;
ar.Undef = 0;
} else if (a1->Undef == 0 && a1->Value) {
ar.Value = 1;
ar.Undef = 0;
} else {
ar.Value = 0;
}
break;
default:
cerror(EFATAL_ERROR_PARSING_EXP);
break;
}
} else {
ar.Undef = a1->Undef;
switch(op->Token) {
case '!':
ar.Value = !a1->Value;
break;
case '~':
ar.Value = ~a1->Value;
break;
case CUMI:
ar.Value = -a1->Value;
break;
case '(':
ar.Value = a1->Value;
break;
case CDEFINED:
ar.Undef = 0;
if (a1->Undef)
ar.Value = 0;
else
ar.Value = 1;
break;
default:
cerror(EFATAL_ERROR_PARSING_EXP);
break;
}
}
AtomStack[AtomIdx++] = ar;
dbprintf(("op %c %03x result %ld (%d)\n", op->Token, op->Token, ar.Value, ar.Undef));
return(0);
}
int
GetAtomStack(pundef, pv)
short *pundef;
long *pv;
{
Atom *at;
if (AtomIdx <= BaseAtomIdx) {
if (pundef)
*pundef = 1;
return(-1);
}
at = AtomStack + --AtomIdx;
if (pundef)
*pundef = at->Undef;
if (pv)
*pv = at->Value;
return(0);
}
int
ParseCharConst(buf, i, max, pv)
char *buf;
long i;
long max;
long *pv;
{
ubyte c;
long v = 0;
if (buf[i] != '\'')
return(0);
++i;
while (i < max && (c = buf[i]) != '\'') {
++i;
if (c == '\\' && i < max) {
c = buf[i++];
switch(c) {
case 'a':
c = 7;
break;
case 'b':
c = 8;
break;
case 'f':
c = 'f'&0x1F;
break;
case 'n':
c = 10;
break;
case 'r':
c = 13;
break;
case 't':
c = 9;
break;
case 'v':
c = 11;
break;
case 'x':
{
short n;
short r = 0;
short cnt = 2;
while (cnt && (n = HexDig(c)) > 0) {
r = (r << 4) + n;
c = buf[i++];
--cnt;
}
if (cnt)
--i;
c = r;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
short cnt;
short r;
short n;
for (r = cnt = 0; cnt < 3 && (n = OctDig(c)) >= 0; ++cnt) {
r = (r << 3) + n;
c = buf[i++];
}
--i;
c = r;
}
break;
default:
c = buf[i];
break;
}
}
v = (v << 8) | c;
}
*pv = v;
if (i < max) /* skip closing single quote */
++i;
else
cerror(EERROR_UNTERMINATED_CHARCONST);
return(i);
}
/*
* 0xhex
* 0octal
* 1-9decimal
*/
int
ParseInt(buf, i, max, pv)
char *buf;
long i;
long max;
long *pv;
{
char c;
long v = 0;
if (i < max && buf[i] == '0') {
++i;
if (i < max && (buf[i] == 'x' || buf[i] == 'X')) { /* hex */
short n;
++i;
while (i < max && (n = HexDig(buf[i])) >= 0) {
v = (v << 4) + n;
++i;
}
} else { /* oct */
short n;
while (i < max && (n = OctDig(buf[i])) >= 0) {
v = (v << 3) + n;
++i;
}
}
} else {
while (i < max && (c = buf[i]) >= '0' && c <= '9') { /* dec */
v = v * 10 + c - '0';
++i;
}
}
while ((c = buf[i]) == 'L' || c == 'l' || c == 'U' || c == 'u')
++i;
*pv = v;
return(i);
}
int
HexDig(char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
if (c >= 'a' && c <= 'f')
c = c + ('A' - 'a');
if (c >= 'A' && c <= 'F')
return (c + (10 - 'A'));
return(-1);
}
int
OctDig(char c)
{
if (c >= '0' && c <= '7')
return (c - '0');
return(-1);
}